Abstract
Part of theR for Artists and Designers workshop course at the School of Foundation Studies, Srishti Manipal Institute of Art, Design, and Technology, Bangalore.
This RMarkdown document is part of the Generic Skills Component (GSK) of the Course of the Foundation Studies Programme at Srishti Manipal Institute of Art, Design, and Technology, Bangalore India. The material is based on A Layered Grammar of Graphics by Hadley Wickham. The course is meant for First Year students pursuing a Degree in Art and Design.
The intent of this GSK part is to build Skill in coding in R, and also appreciate R as a way to metaphorically visualize information of various kinds, using predominantly geometric figures and structures.
All RMarkdown files combine code, text, web-images, and figures developed using code. Everything is text; code chunks are enclosed in fences (```)
At the end of this Lab session, we should: - know the types and structures of spatial data and be able to work with them - understand the basics of modern spatial packages in R - be able to specify and download spatial data from the web, using R from sources such as naturalearth and Open Streep Map - plot static and interactive maps using ggplot, tmap and leaflet packages - add symbols and markers for places and regions of our own interest in these maps. - see directions for further work (e.g. maps + networks together)
The method followed will be based on PRIMM:
parameters of the code do and write comments to explain. What bells and whistles can you see?parameters code provided to understand the options available. Write comments to show what you have aimed for and achieved.The setup code chunk below brings into our coding session R packages that provide specific computational abilities and also datasets which we can use.
To reiterate: Packages and datasets are not the same thing !! Packages are (small) collections of programs. Datasets are just….information.
We will take small steps in making maps using just two of the several map making packages in R.
The steps we will use are:
osmdataggplot and tmapleaflet using a variety of map data providers. Note: tmap can also do interactive maps which we will explore also.Bas. Onwards and Map-wards!!
All jargon words will be capitalized and in bold font.
In R, we need to specify a “BOUNDING BOX” first, to declare our area of interest. God made me a BengaluR-kaR…I think..Let’s see if we can declare an area of interest. Then we can order on Swiggy and…never mind.
We can declare a BOUNDING BOX in several ways, using a variety of R packages.
# BLR Bounding Box using `osmplotr` package
# get_bbox is a command from the `osmplotr` package
# get_bbox needs lat and lon ranges
# Format is c(min-lon, min-lat, max-lon, max-lat)
bbox_1 <- osmplotr::get_bbox(latlon = c(77.46,12.83,77.74,13.14))
bbox_1
## min max
## x 77.46 77.74
## y 12.83 13.14
# Using getbb command from the osmdata package
bbox_2 <- osmdata::getbb("Jayanagar, Bangalore, India")
bbox_2
## min max
## x 77.56242 77.60242
## y 12.90927 12.94927
# Using searchbbox command from the prettymapr package
bbox_3 <- prettymapr::searchbbox("Jayanagar, Bangalore, India")
bbox_3
## min max
## x 77.56242 77.60242
## y 12.90927 12.94927
Let us examine all the calculated BOUNDING BOXes
bbox_1
## min max
## x 77.46 77.74
## y 12.83 13.14
bbox_2
## min max
## x 77.56242 77.60242
## y 12.90927 12.94927
bbox_3
## min max
## x 77.56242 77.60242
## y 12.90927 12.94927
bbox_1 is quite big: 0.3 degrees range in both lon and lat. bbox_2 and bbox_3 are identical and also reasonably sized: 0.04 degrees in longitude range and in latitude range.
We will use the bbox_3 from the above, to ensure we have smaller data downloads!
Within our bbox for Jayanagar, Bangalore, we want to download diverse kinds of FEATURE data. Remember that a FEATURE is any object that can be “seen” on a map. This is done using the osmplotr::extract_osm_objects() command. The main parameters for this command are:
We will get the map data from OSM and then save it avoid repeated downloads. So, please copy/paste and run the following commands in your console. Do not run these commands too many times. Re-run this ONLY if you have changed your BOUNDING BOX.
dat_buildings <-extract_osm_objects (key = "building",
bbox = bbox_3,)
dat_roads <- extract_osm_objects (key = 'highway',
value = c("residential"),
bbox = bbox_3)
dat_parks <- extract_osm_objects (key = 'park',
bbox = bbox_3)
dat_greenery <- extract_osm_objects (key = 'landuse',
value = 'grass',
bbox = bbox_3)
dat_trees <- extract_osm_objects (key = 'natural',
value = 'tree',
bbox = bbox_3)
We will store the downloaded data as .gpkg files on our local hard drives to use when we run this file again later.
st_write(dat_buildings,
dsn = "buildings.gpkg",
append = FALSE,
quiet = FALSE)
## Deleting layer `buildings' using driver `GPKG'
## Writing layer `buildings' to data source `buildings.gpkg' using driver `GPKG'
## Writing 34752 features with 81 fields and geometry type Polygon.
st_write(dat_parks, dsn = "parks.gpkg", append = FALSE, quiet = FALSE)
## Deleting layer `parks' using driver `GPKG'
## Writing layer `parks' to data source `parks.gpkg' using driver `GPKG'
## Writing 57 features with 23 fields and geometry type Polygon.
st_write(dat_greenery, dsn = "greenery.gpkg", append = FALSE,quiet = FALSE)
## Deleting layer `greenery' using driver `GPKG'
## Writing layer `greenery' to data source `greenery.gpkg' using driver `GPKG'
## Writing 2 features with 2 fields and geometry type Polygon.
st_write(dat_trees, dsn = "trees.gpkg", append = FALSE,quiet = FALSE)
## Deleting layer `trees' using driver `GPKG'
## Writing layer `trees' to data source `trees.gpkg' using driver `GPKG'
## Writing 153 features with 8 fields and geometry type Point.
st_write(dat_roads, dsn = "roads.gpkg", append = FALSE, quiet = FALSE)
## Deleting layer `roads' using driver `GPKG'
## Writing layer `roads' to data source `roads.gpkg' using driver `GPKG'
## Writing 2161 features with 27 fields and geometry type Line String.
Always work from here to avoid repeated downloads from OSM.
buildings <- st_read("./buildings.gpkg")
## Reading layer `buildings' from data source
## `C:\Users\Arvind\My Drive\R work\MyWebsites\R-for-Artists-and-Designers\static\labs\buildings.gpkg'
## using driver `GPKG'
## Simple feature collection with 34752 features and 81 fields
## Geometry type: POLYGON
## Dimension: XY
## Bounding box: xmin: 77.56221 ymin: 12.90906 xmax: 77.60373 ymax: 12.9497
## Geodetic CRS: WGS 84
parks <- st_read("./parks.gpkg")
## Reading layer `parks' from data source
## `C:\Users\Arvind\My Drive\R work\MyWebsites\R-for-Artists-and-Designers\static\labs\parks.gpkg'
## using driver `GPKG'
## Simple feature collection with 57 features and 23 fields
## Geometry type: POLYGON
## Dimension: XY
## Bounding box: xmin: 77.56196 ymin: 12.90692 xmax: 77.60389 ymax: 12.95397
## Geodetic CRS: WGS 84
greenery <- st_read("./greenery.gpkg")
## Reading layer `greenery' from data source
## `C:\Users\Arvind\My Drive\R work\MyWebsites\R-for-Artists-and-Designers\static\labs\greenery.gpkg'
## using driver `GPKG'
## Simple feature collection with 2 features and 2 fields
## Geometry type: POLYGON
## Dimension: XY
## Bounding box: xmin: 77.56776 ymin: 12.91751 xmax: 77.57392 ymax: 12.94811
## Geodetic CRS: WGS 84
trees <- st_read("./trees.gpkg")
## Reading layer `trees' from data source
## `C:\Users\Arvind\My Drive\R work\MyWebsites\R-for-Artists-and-Designers\static\labs\trees.gpkg'
## using driver `GPKG'
## Simple feature collection with 153 features and 8 fields
## Geometry type: POINT
## Dimension: XY
## Bounding box: xmin: 77.56566 ymin: 12.90806 xmax: 77.60096 ymax: 12.94914
## Geodetic CRS: WGS 84
roads <- st_read("./roads.gpkg")
## Reading layer `roads' from data source
## `C:\Users\Arvind\My Drive\R work\MyWebsites\R-for-Artists-and-Designers\static\labs\roads.gpkg'
## using driver `GPKG'
## Simple feature collection with 2161 features and 27 fields
## Geometry type: LINESTRING
## Dimension: XY
## Bounding box: xmin: 77.55895 ymin: 12.90634 xmax: 77.60603 ymax: 12.95636
## Geodetic CRS: WGS 84
How many rows? ( Rows -> Features ) What kind of geom column?
# How many buildings?
nrow(buildings)
## [1] 34752
buildings$geom
## Geometry set for 34752 features
## Geometry type: POLYGON
## Dimension: XY
## Bounding box: xmin: 77.56221 ymin: 12.90906 xmax: 77.60373 ymax: 12.9497
## Geodetic CRS: WGS 84
## First 5 geometries:
class(buildings$geom)
## [1] "sfc_POLYGON" "sfc"
So the buildings dataset has 34752 buildings and their geometry is naturally a POLYGON type of geometry column.
Do this check for all the other spatial data, in the code chunk below. What kind of geom column does each dataset have?
osm_structures returns a data.frame of OSM structure types, associated key-value pairs and unique suffixes which may be appended to data structures/filenames for storage purposes, and suggested colours.
osmplotr::osm_structures()
We can use these key-value pairs to download different types of map data.
There are two ways of plotting maps that we will learn:
First we will plot with ggplot and geom_sf() : recall that our data is stored in 5 files: buildings, parks, roads, trees, and greenery.
ggplot() +
geom_sf(data = buildings, colour = "orange") + # POLYGONS
geom_sf(data = roads, col = "gray20") + # LINES
geom_sf(data = parks, col = "darkseagreen1") + # POLYGONS
geom_sf(data = greenery, col = "darkseagreen") + # POLYGONS
geom_sf(data = trees, col = "green") # POINTS
Note how geom_sf is capable of handling any geometry in the sfc column !!
geom_sf()is an unusual geom because it will draw different geometric objects depending on what simple features are present in the data: you can get points, lines, or polygons.
So there, we have our first map!
tmap packageWe can also create a map using a package called tmap. Here we also have the option of making the map interactive.
tmap plots are made with code in “groups”: each group starts with a tm_shape() command.
# Group-1
tm_shape(buildings) +
tm_fill(col = "mediumblue") +
#Group-2
tm_shape(roads) +
tm_lines(col = "gold") +
#Group-3
tm_shape(greenery) +
tm_polygons(col = "limegreen") +
#Group-4
tm_shape(parks) +
tm_polygons(col = "limegreen") +
#Group-5
tm_shape(trees) +
tm_dots(col = "green")
How do we make this map interactive? One more line of code !! Add this line in your console and then run the above chunk again
tmap_mode(“view”)
tmapLike many other packages ( e.g. ggplot ) tmap also has a few built-in spatial datasets: World and metro, rivers, land and a few others. Check help on these. Let’s plot a first map using datasets built into tmap.
data("World")
head(World, n = 3)
We have several 14 attribute variables in World. Attribute variables such as gdp_cap_est, HPI are numeric. Others such as income_grp appear to be factors. iso_a3 is the standard three letter name for the country. name is of course, the name for each country!
data("metro")
head(metro, n = 3)
Here too we have attribute variables for the metros, and they seem predominantly numeric. Again iso_a3 is the three letter name for the city.
tmap_mode("plot") # Making this a static plot
# Group 1
tm_shape(World) + # dataset = World.
tm_polygons("HPI") + # Colour polygons by HPI numeric variable
# Note the "+" sign continuation
# Group 2
tm_shape(metro) + # dataset = metro
tm_bubbles(size = "pop2030",
col = "red")
# Plot cities as bubbles
# Size proportional to numeric variable `pop2030`
tmap_mode("view") # Change to Interactive
# Let's use WaterColor Map this time!!
tm_tiles("Stamen.Watercolor") + # Watercolor map only with interactive
tm_shape(World) +
tm_polygons("HPI") + # Color by Happiness Index
tm_shape(metro) +
tm_bubbles(size = "pop2030", # Size City Markers by Population in 2020
col = "red")
rnaturalearthThe rnaturalearth package allows us to download shapes of countries. We can use it to get borders and also internal state/district boundaries.
india <-
ne_states(country = "india",
returnclass = "sf") # gives a ready sf dataframe !
india_neighbours <-
ne_states(country = (c("sri lanka", "pakistan",
"afghanistan", "nepal","bangladesh", "bhutan")
),
returnclass = "sf")
Let’s look at the attribute variable columns to colour our graph and to shape our symbols:
names(india)
## [1] "featurecla" "scalerank" "adm1_code" "diss_me" "iso_3166_2"
## [6] "wikipedia" "iso_a2" "adm0_sr" "name" "name_alt"
## [11] "name_local" "type" "type_en" "code_local" "code_hasc"
## [16] "note" "hasc_maybe" "region" "region_cod" "provnum_ne"
## [21] "gadm_level" "check_me" "datarank" "abbrev" "postal"
## [26] "area_sqkm" "sameascity" "labelrank" "name_len" "mapcolor9"
## [31] "mapcolor13" "fips" "fips_alt" "woe_id" "woe_label"
## [36] "woe_name" "latitude" "longitude" "sov_a3" "adm0_a3"
## [41] "adm0_label" "admin" "geonunit" "gu_a3" "gn_id"
## [46] "gn_name" "gns_id" "gns_name" "gn_level" "gn_region"
## [51] "gn_a1_code" "region_sub" "sub_code" "gns_level" "gns_lang"
## [56] "gns_adm1" "gns_region" "min_label" "max_label" "min_zoom"
## [61] "wikidataid" "name_ar" "name_bn" "name_de" "name_en"
## [66] "name_es" "name_fr" "name_el" "name_hi" "name_hu"
## [71] "name_id" "name_it" "name_ja" "name_ko" "name_nl"
## [76] "name_pl" "name_pt" "name_ru" "name_sv" "name_tr"
## [81] "name_vi" "name_zh" "ne_id" "geometry"
names(india_neighbours)
## [1] "featurecla" "scalerank" "adm1_code" "diss_me" "iso_3166_2"
## [6] "wikipedia" "iso_a2" "adm0_sr" "name" "name_alt"
## [11] "name_local" "type" "type_en" "code_local" "code_hasc"
## [16] "note" "hasc_maybe" "region" "region_cod" "provnum_ne"
## [21] "gadm_level" "check_me" "datarank" "abbrev" "postal"
## [26] "area_sqkm" "sameascity" "labelrank" "name_len" "mapcolor9"
## [31] "mapcolor13" "fips" "fips_alt" "woe_id" "woe_label"
## [36] "woe_name" "latitude" "longitude" "sov_a3" "adm0_a3"
## [41] "adm0_label" "admin" "geonunit" "gu_a3" "gn_id"
## [46] "gn_name" "gns_id" "gns_name" "gn_level" "gn_region"
## [51] "gn_a1_code" "region_sub" "sub_code" "gns_level" "gns_lang"
## [56] "gns_adm1" "gns_region" "min_label" "max_label" "min_zoom"
## [61] "wikidataid" "name_ar" "name_bn" "name_de" "name_en"
## [66] "name_es" "name_fr" "name_el" "name_hi" "name_hu"
## [71] "name_id" "name_it" "name_ja" "name_ko" "name_nl"
## [76] "name_pl" "name_pt" "name_ru" "name_sv" "name_tr"
## [81] "name_vi" "name_zh" "ne_id" "geometry"
# Look only at attributes
india %>% st_drop_geometry() %>% head()
india_neighbours%>% st_drop_geometry() %>% head()
In the india data frame: - Column iso_a2 contains the country name. - Column name contains the name of the state
In the india_neighbours data frame: - Column gu_a3 contains the country abbreviation - Column name contains the name of the state - Column iso_3166_2 contains the abbreviation of the state within each neighbouring country.
tmap_mode("view")
# Plot India
tm_shape(india) +
tm_polygons("name", # Colour by States in India
legend.show = FALSE) +
# Plot Neighbours
tm_shape(india_neighbours) +
tm_fill(col = "gu_a3") + # Colour by Country Name
# Plot the cities in India alone
tm_shape(metro %>% dplyr::filter(iso_a3 == "IND")) +
tm_dots(size = "pop2020",legend.size.show = FALSE) +
# size by population in 2020
tm_layout(legend.show = FALSE) +
tm_credits("Geographical Boundaries are not accurate",
size = 0.5,
position = "right") +
tm_compass(position = c("right", "top")) +
tm_scale_bar(position = "left") +
tmap_style(style = "classic")
## Warning: Number of levels of the variable "name" is 35, which is
## larger than max.categories (which is 30), so levels are combined. Set
## tmap_options(max.categories = 35) in the layer function to show all levels.
#Try other map styles
#cobalt #gray #white #watercolor #beaver #classic #watercolor #albatross #bw #col_blind
Can you try to download a map area of your home town and plot it as we have above?
Is it time to order on Swiggy…
Let us adding interesting places to our map: say based on your favourite restaurants etc. We need restaurant data: lat/long + name + maybe type of restaurant. This can be manually created ( like all of OSMdata ) or if it is already there we can download using key-value pairs in our OSM data query. Restaurants can be downloaded using key= "amenity", value = "restaurant". Since we want JUST their location, and not the restaurant BUILDINGs, we say return_type = "points".
There are also other tags to explore!Searching for McDonalds for instance…( key = “name”, value = “McDonalds”)
dat_R <- extract_osm_objects(bbox = bbox_3,
key = "amenity",
value = "restaurant",
return_type = "point") #<<
# Save the data for future use
write_sf(dat_R, dsn = "restaurants.gpkg",append = FALSE, quiet = FALSE)
## Deleting layer `restaurants' using driver `GPKG'
## Writing layer `restaurants' to data source `restaurants.gpkg' using driver `GPKG'
## Writing 205 features with 33 fields and geometry type Point.
Note the return_type parameter: we want the location and not the building in which the restaurant is!!
restaurants <- st_read("./restaurants.gpkg")
## Reading layer `restaurants' from data source
## `C:\Users\Arvind\My Drive\R work\MyWebsites\R-for-Artists-and-Designers\static\labs\restaurants.gpkg'
## using driver `GPKG'
## Simple feature collection with 205 features and 33 fields
## Geometry type: POINT
## Dimension: XY
## Bounding box: xmin: 77.56373 ymin: 12.9105 xmax: 77.60104 ymax: 12.94917
## Geodetic CRS: WGS 84
How many restaurants have we got?
restaurants %>% nrow()
## [1] 205
These are the columns in the Restaurant Data:
names(restaurants)
## [1] "osm_id" "name" "addr.city"
## [4] "addr.housename" "addr.housenumber" "addr.postcode"
## [7] "addr.street" "alt_name" "amenity"
## [10] "building" "capacity" "cuisine"
## [13] "delivery" "description" "diet.vegetarian"
## [16] "email" "food" "internet_access"
## [19] "level" "name.en" "name.kn"
## [22] "note" "opening_hours" "operator"
## [25] "phone" "smoking" "source"
## [28] "takeaway" "toilets.wheelchair" "website"
## [31] "wheelchair" "wikidata" "wikipedia"
## [34] "geom"
So let us plot the restaurants as POINTs using the restaurants data we have downloaded. The cuisine attribute looks interesting; let us colour the POINT based on the cuisine offered at that restaurant.
So Let’s look therefore at the cuisine column!
# ( I want pizza...)
restaurants$cuisine
## [1] NA
## [2] NA
## [3] "indian"
## [4] "italian"
## [5] NA
## [6] "indian"
## [7] "indian"
## [8] "regional"
## [9] "indian"
## [10] NA
## [11] NA
## [12] NA
## [13] NA
## [14] NA
## [15] NA
## [16] NA
## [17] "pizza"
## [18] NA
## [19] NA
## [20] NA
## [21] NA
## [22] NA
## [23] "regional"
## [24] "ice_cream"
## [25] "ice_cream"
## [26] NA
## [27] NA
## [28] NA
## [29] "indian"
## [30] "chinese"
## [31] NA
## [32] NA
## [33] "pizza"
## [34] NA
## [35] "burger;sandwich"
## [36] NA
## [37] "chinese"
## [38] NA
## [39] NA
## [40] NA
## [41] NA
## [42] NA
## [43] NA
## [44] NA
## [45] NA
## [46] NA
## [47] NA
## [48] "indian"
## [49] NA
## [50] "italian"
## [51] "regional"
## [52] NA
## [53] "indian"
## [54] "indian"
## [55] "italian"
## [56] "regional"
## [57] "indian"
## [58] "chinese"
## [59] "indian"
## [60] NA
## [61] "indian"
## [62] "indian"
## [63] "indian"
## [64] NA
## [65] "indian"
## [66] NA
## [67] NA
## [68] "ice_cream"
## [69] "pizza"
## [70] NA
## [71] "South_Indian"
## [72] "regional"
## [73] "regional"
## [74] NA
## [75] NA
## [76] NA
## [77] NA
## [78] NA
## [79] NA
## [80] NA
## [81] NA
## [82] NA
## [83] NA
## [84] NA
## [85] NA
## [86] NA
## [87] NA
## [88] NA
## [89] NA
## [90] NA
## [91] NA
## [92] NA
## [93] NA
## [94] NA
## [95] NA
## [96] "Multi-cuisne"
## [97] "South_India"
## [98] "indian"
## [99] "indian"
## [100] "chicken;regional"
## [101] NA
## [102] "arab"
## [103] "indian"
## [104] NA
## [105] NA
## [106] NA
## [107] "regional"
## [108] "regional"
## [109] NA
## [110] "regional"
## [111] "regional"
## [112] "regional"
## [113] "indian;seafood;fine_dining"
## [114] "indian"
## [115] "indian"
## [116] "indian"
## [117] "regional"
## [118] "regional"
## [119] "italian"
## [120] "regional"
## [121] "regional"
## [122] "regional"
## [123] "regional"
## [124] "regional"
## [125] "regional"
## [126] "regional"
## [127] "regional"
## [128] "regional"
## [129] "regional"
## [130] "regional"
## [131] "regional"
## [132] "fast_food"
## [133] "indian"
## [134] "regional"
## [135] "italian"
## [136] "regional"
## [137] "regional"
## [138] "regional"
## [139] "regional"
## [140] "regional"
## [141] "regional"
## [142] "italian"
## [143] "fast_food"
## [144] "regional"
## [145] "fast_food"
## [146] "regional"
## [147] "chinese"
## [148] NA
## [149] "regional"
## [150] "regional"
## [151] "regional"
## [152] "regional"
## [153] "regional"
## [154] "regional"
## [155] "regional"
## [156] "regional"
## [157] "regional"
## [158] "regional"
## [159] "regional"
## [160] "regional"
## [161] "regional"
## [162] "regional"
## [163] "regional"
## [164] "regional"
## [165] "regional"
## [166] "regional"
## [167] "regional"
## [168] "regional"
## [169] "kebab;grill"
## [170] "chicken"
## [171] "chinese;sandwich;tea;indian;coffee_shop"
## [172] NA
## [173] "indian,_japanese"
## [174] "italian"
## [175] NA
## [176] NA
## [177] NA
## [178] NA
## [179] NA
## [180] NA
## [181] NA
## [182] NA
## [183] NA
## [184] NA
## [185] NA
## [186] NA
## [187] NA
## [188] NA
## [189] NA
## [190] NA
## [191] NA
## [192] NA
## [193] NA
## [194] NA
## [195] NA
## [196] NA
## [197] NA
## [198] "indian"
## [199] NA
## [200] NA
## [201] NA
## [202] NA
## [203] NA
## [204] NA
## [205] "indian;regional"
Big mess…many NAs, some double entries, separated by commas and semicolons….
cuisine attribute:
cuisine variable has more than one entry for a given restaurant. We use tidyr::separate() to make multiple columns out of the cuisine column and retain the first one only. Since the entries are badly entered using both “;” and “,” we need to do this twice ;-() Bad Data entry!!
Let’s get one cuisine entry per restaurant, and drop off the ones that do not mention a cuisine at all:
restaurants <- restaurants %>%
drop_na(cuisine) %>% # Knock off nondescript restaurants
# Some have more than one classification ;-()
# Separated by semicolon or comma, so....
separate(col = cuisine, into = c("cuisine", NA, NA), sep = ";") %>%
separate(col = cuisine, into = c("cuisine", NA, NA), sep = ",")
## Warning: Expected 3 pieces. Additional pieces discarded in 1 rows [104].
## Warning: Expected 3 pieces. Missing pieces filled with `NA` in 106 rows [1, 2,
## 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...].
## Warning: Expected 3 pieces. Missing pieces filled with `NA` in 108 rows [1, 2,
## 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...].
# Finally good food?
restaurants$cuisine
## [1] "indian" "italian" "indian" "indian" "regional"
## [6] "indian" "pizza" "regional" "ice_cream" "ice_cream"
## [11] "indian" "chinese" "pizza" "burger" "chinese"
## [16] "indian" "italian" "regional" "indian" "indian"
## [21] "italian" "regional" "indian" "chinese" "indian"
## [26] "indian" "indian" "indian" "indian" "ice_cream"
## [31] "pizza" "South_Indian" "regional" "regional" "Multi-cuisne"
## [36] "South_India" "indian" "indian" "chicken" "arab"
## [41] "indian" "regional" "regional" "regional" "regional"
## [46] "regional" "indian" "indian" "indian" "indian"
## [51] "regional" "regional" "italian" "regional" "regional"
## [56] "regional" "regional" "regional" "regional" "regional"
## [61] "regional" "regional" "regional" "regional" "regional"
## [66] "fast_food" "indian" "regional" "italian" "regional"
## [71] "regional" "regional" "regional" "regional" "regional"
## [76] "italian" "fast_food" "regional" "fast_food" "regional"
## [81] "chinese" "regional" "regional" "regional" "regional"
## [86] "regional" "regional" "regional" "regional" "regional"
## [91] "regional" "regional" "regional" "regional" "regional"
## [96] "regional" "regional" "regional" "regional" "regional"
## [101] "regional" "kebab" "chicken" "chinese" "indian"
## [106] "italian" "indian" "indian"
Looks clean! Each entry is only ONE and not multiple any more. Now let’s plot the Restaurants as POINTs:
# http://www.stat.columbia.edu/~tzheng/files/Rcolor.pdf
#
ggplot() +
geom_sf(data = buildings, colour = "burlywood1") +
geom_sf(data = roads, colour = "gray80") +
geom_sf(data = restaurants %>% drop_na(cuisine), aes(fill = cuisine), colour = "black", shape = 21, size = 3) +
theme(legend.position = "right") +
labs(title = "Restaurants in South Central Bangalore",
caption = "Based on osmdata")
We could have done a (much!) better job, by combining cuisines into simpler and fewer categories, ( South_India and South_Indian ), but that is for another day!!
By now we know that we can use geom_sf() multiple number of times with different datasets to create layered maps in R.
Emine Fidan, Guide to Creating Interactive Maps in R
Nikita Voevodin,R, Not the Best Practices